/***************************************************************************
 *   Copyright (C) 2008 by BogDan Vatra                                    *
 *   bogdan@licentia.eu                                                    *
 *                                                                         *
 *   This program is free software: you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation, either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/
#include <QShowEvent>
#include <QCompleter>
#include <QAbstractItemView>
#include <QItemSelectionModel>
#include <QTableView>

#include "lookuplineedit.h"
#include "validator.h"
#include "query.h"
#include "listview.h"
#include "infoview.h"
#include "querylocateselectionmodel.h"

using namespace SQL;

LookupLineEdit::LookupLineEdit(QWidget *parent)
		: QLineEdit(parent), m_sortedListField(true), m_validator(0), m_completer(0), m_infoView(0), m_lq(0), m_dq(0),m_validateInput(false),m_handleFocus(true)
{
	connect(this, SIGNAL(editingFinished()), SLOT(bindValue()));
}


LookupLineEdit::~LookupLineEdit()
{
	delete m_infoView;
}

bool LookupLineEdit::handleFocus()
{
	return m_handleFocus;
}

void LookupLineEdit::setHandleFocus(bool handleFocus)
{
	m_handleFocus=handleFocus;
}


void LookupLineEdit::setValidateInput(bool validate)
{
	m_validateInput=validate;
}

bool LookupLineEdit::validateInput()
{
	return m_validateInput;
}

void LookupLineEdit::showEvent(QShowEvent * event)
{
	QLineEdit::showEvent(event);

	if (!event->isAccepted())
		return;

	if(m_dq || m_validateInput)
	{
		if (!m_validator)
			m_validator = new Validator(m_listQuery, m_listField, m_sortedListField, m_appendPluginName, this);
		setValidator(m_validator);
	}

	if (!m_completer && m_lq)
	{
		m_completer = new QCompleter(this);
		m_completer->setModel(m_lq->createModel(QStringList() << m_listField << m_infoFields));
		m_completer->setPopup(new ListView);
		m_completer->setCaseSensitivity(Qt::CaseInsensitive);
		QueryLocateSelectionModel * ism = new QueryLocateSelectionModel(m_completer->completionModel(), m_lq, m_listField, m_sortedListField, this );
		m_completer->popup()->setSelectionModel(ism);
		if (m_infoFields.size())
		{
			m_infoView = new InfoView(m_completer->popup());
			m_infoView->setSelectionModel(ism);
			m_infoView->setInfoHeads(m_infoHeads);
		}
	}
	setCompleter(m_completer);
}

QString LookupLineEdit::listQuery()
{
	return m_listQuery;
}

void LookupLineEdit::setListQuery(const QString & listQuery)
{
	m_listQuery = listQuery;
	m_lq = defaultDatabase()->query(listQuery);
	if (!m_lq)
		return;;
	connect(m_lq, SIGNAL(recordChanged(const QSqlRecord& )),SLOT(listRecordChanged(const QSqlRecord&)));
	setTextToEdit();
}

QString LookupLineEdit::listField()
{
	return m_listField;
}

void LookupLineEdit::setListField(const QString & listField)
{
	m_listField = listField;
	setTextToEdit();
}


bool LookupLineEdit::isSortedListField()
{
	return m_sortedListField;
}

void LookupLineEdit::setSortedListField(bool sortedListField)
{
	m_sortedListField = sortedListField;
}


QStringList LookupLineEdit::infoFields()
{
	return m_infoFields;
}

void LookupLineEdit::setInfoFields(const QStringList & infoFields)
{
	m_infoFields = infoFields;
}


QStringList LookupLineEdit::infoHeads()
{
	return m_infoHeads;
}

void LookupLineEdit::setInfoHeads(const QStringList & infoHeads)
{
	m_infoHeads = infoHeads;
}


QString LookupLineEdit::keyField()
{
	return m_keyField;
}

void LookupLineEdit::setKeyField(const QString & keyField)
{
	m_keyField = keyField;
	setTextToEdit();
}


QString LookupLineEdit::appendPluginName()
{
	return m_appendPluginName;
}

void LookupLineEdit::setAppendPluginName(const QString & appendPluginName)
{
	m_appendPluginName = appendPluginName;
}

QString LookupLineEdit::dataQuery()
{
	return m_dataQuery;
}

void LookupLineEdit::setDataQuery(const QString & dataQuery)
{
	m_dataQuery = dataQuery;
	m_dq = defaultDatabase()->query(m_dataQuery);

	if (!m_dq)
		return;

//	connect(m_dq, SIGNAL(recordChanged(const QSqlRecord&)), SLOT(recordChanged()));
	connect(m_dq, SIGNAL(cursorSeek(int)), SLOT(recordChanged()));
	connect(m_dq, SIGNAL(beforeInsert()), SLOT(setReadWrite()));
	connect(m_dq, SIGNAL(beforeUpdate()), SLOT(setReadWrite()));
	connect(m_dq, SIGNAL(afterSelect()), SLOT(setReadOnly()));
	connect(m_dq, SIGNAL(afterClose()), SLOT(setReadOnly()));
	connect(m_dq, SIGNAL(afterPost()), SLOT(setReadOnly()));
	connect(m_dq, SIGNAL(afterCancel()), SLOT(setReadOnly()));
	setDisabled(m_dq->state() == Query::Select || m_dq->state() == Query::Invalid );
	setTextToEdit();
}

QString LookupLineEdit::dataField()
{
	return m_dataField;
}

void LookupLineEdit::setDataField(const QString & dataField)
{
	m_dataField = dataField;
	setTextToEdit();
}

void LookupLineEdit::setTextToEdit()
{
	clear();
	if (!m_lq || !m_listField.length() || !m_keyField.length() || m_lq->state() != Query::Select )
		return;
	if (m_dq && m_dataField.length() && m_dq->state() == Query::Select && m_dq->value(m_dataField) != m_lq->value(m_keyField))
		if (!m_lq->locate(m_keyField, m_dq->value(m_dataField), false, false, false))
			return;

	setText(m_lq->value(m_listField).toString());
	setAlignment(Query::typeIsNumber(m_lq->value(m_listField).type()) ? Qt::AlignRight : Qt::AlignLeft);
}

void LookupLineEdit::setReadWrite()
{
	setEnabled(true);
	if (!m_lq || !m_dq || !m_dataField.length() || !m_listField.length() || !m_keyField.length() || m_lq->state() != Query::Select )
		return;

	if (m_dq->state() == Query::Insert)
	{
		m_lq->first();
		m_dq->setValue(m_dataField, m_lq->value(m_keyField));
		setText(m_lq->value(m_listField).toString());
		setAlignment(Query::typeIsNumber(m_lq->value(m_listField).type()) ? Qt::AlignRight : Qt::AlignLeft);
	}
}

void LookupLineEdit::focusInEvent(QFocusEvent * event)
{
	if (m_dq && m_dq->state() == Query::Update)
	{
		setCursorPosition(0);
		selectAll();
	}
	QLineEdit::focusInEvent(event);
	if (event->isAccepted())
		emit(focusIn());
}

void LookupLineEdit::focusOutEvent(QFocusEvent * event)
{
	if (m_lq && m_lq->state() == Query::Select && m_listField.length())
		setText(m_lq->value(m_listField).toString());
	QLineEdit::focusOutEvent(event);
	if (event->isAccepted())
		emit(focusOut());
}

void LookupLineEdit::setReadOnly()
{
	setDisabled(true);
// 	if (!m_lq || !m_dq || !m_dataField.length() || !m_listField.length() || !m_keyField.length() || m_lq->state() != Query::Select )
// 		return;

/*
	if (m_dq->state() == Query::Select)
	{
		if (m_dq->value(m_dataField) != m_lq->value(m_keyField))
			if (!m_lq->locate(m_keyField, m_dq->value(m_dataField), false, false, false))
				return;
		setText(m_lq->value(m_listField).toString());
		setAlignment(Query::typeIsNumber(m_lq->value(m_listField).type()) ? Qt::AlignRight : Qt::AlignLeft);
	}*/
}

void LookupLineEdit::listRecordChanged(const QSqlRecord& /*record*/)
{
	if (m_lq->state() != Query::Select || !m_listField.length() || (m_dq && m_dq->state() != Query::Insert && m_dq->state() != Query::Update ))
		return;
	setText(m_lq->value(m_listField).toString());
	bindValue();
}


void LookupLineEdit::recordChanged()
{

	clear();
	if (!m_lq || !m_dq || !m_dataField.length() || !m_listField.length() || !m_keyField.length() || m_lq->state() != Query::Select )
		return;
	if (m_dq->state() == Query::Select)
	{
		if (m_dq->value(m_dataField) != m_lq->value(m_keyField))
			if (!m_lq->locate(m_keyField, m_dq->value(m_dataField), false, false, false))
			{
				setText(m_lq->value(m_listField).toString());
				return;
			}
		setText(m_lq->value(m_listField).toString());
		setAlignment(Query::typeIsNumber(m_lq->value(m_listField).type()) ? Qt::AlignRight : Qt::AlignLeft);
	}
}

void LookupLineEdit::bindValue()
{
	if (!m_lq || !m_dq || !m_dataField.length() || !m_listField.length() || !m_keyField.length() || m_lq->state() != Query::Select )
		return;
	m_dq->setValue(m_dataField, m_lq->value(m_keyField));
	setText(m_lq->value(m_listField).toString());
}

void LookupLineEdit::keyPressEvent(QKeyEvent * event)
{
	if (event->key() == Qt::Key_Escape)
	{
		if (m_handleFocus)
			 focusPreviousChild();
		emit(escapePressed());
	}
	if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
	{
		if (m_handleFocus && hasFocus())
			 focusNextChild();
		bindValue();
	}
	QLineEdit::keyPressEvent(event);
}
